﻿using FreeSql;
using Microsoft.Extensions.DependencyInjection;
using Rougamo;
using Rougamo.Context;
using System.Data;

namespace Sage.FreeSqlManager.Transaction
{
    /// <summary>
    /// 事务特性 - 用于方法级别的事务控制
    /// </summary>
    /// <remarks>
    /// 支持六种传播方式，可应用于同步和异步方法
    /// </remarks>
    [AttributeUsage(AttributeTargets.Method)]
    public class TransactionalAttribute : MoAttribute
    {
        /// <summary>
        /// 默认构造函数
        /// </summary>
        public TransactionalAttribute()
        {
        }

        /// <summary>
        /// 构造函数 - 允许设置传播方式
        /// </summary>
        /// <param name="propagation">事务传播方式</param>
        public TransactionalAttribute(Propagation propagation)
        {
            Propagation = propagation;
        }

        /// <summary>
        /// 构造函数 - 允许设置传播方式和隔离级别
        /// </summary>
        /// <param name="propagation">事务传播方式</param>
        /// <param name="isolationLevel">事务隔离级别</param>
        public TransactionalAttribute(Propagation propagation, IsolationLevel isolationLevel)
        {
            Propagation = propagation;
            IsolationLevel = isolationLevel;
        }

        /// <summary>
        /// 事务传播方式
        /// </summary>
        /// <value>默认为Required</value>
        public Propagation Propagation { get; set; } = Propagation.Required;

        /// <summary>
        /// 事务隔离级别
        /// </summary>
        /// <value>默认为Unspecified</value>
        public IsolationLevel IsolationLevel
        {
            get => m_IsolationLevel ?? IsolationLevel.Unspecified;
            set => m_IsolationLevel = value;
        }
        private IsolationLevel? m_IsolationLevel;

        // 使用AsyncLocal存储服务提供者，确保异步环境中正确访问
        private static readonly AsyncLocal<IServiceProvider?> m_ServiceProvider = new();

        /// <summary>
        /// 设置服务提供者 - 由中间件调用
        /// </summary>
        /// <param name="serviceProvider">当前请求的服务提供者</param>
        public static void SetServiceProvider(IServiceProvider serviceProvider) => m_ServiceProvider.Value = serviceProvider;

        // 当前工作单元
        private IUnitOfWork? _uow;

        /// <summary>
        /// 方法执行前调用 - 开始事务
        /// </summary>
        /// <param name="context">方法上下文</param>
        public override void OnEntry(MethodContext context)
        {
            Console.WriteLine("开始事务");
            //Console.Write(_uow?.GetType().FullName);

            // 获取服务提供者
            var serviceProvider = m_ServiceProvider.Value
                ?? throw new InvalidOperationException("Service provider not set. Make sure to call SetServiceProvider in middleware.");

            // 获取工作单元管理器并开始事务
            var uowManager = serviceProvider.GetRequiredService<UnitOfWorkManager>();
            _uow = uowManager.Begin(Propagation, m_IsolationLevel);
        }

        /// <summary>
        /// 方法执行后调用 - 提交或回滚事务
        /// </summary>
        /// <param name="context">方法上下文</param>
        public override void OnExit(MethodContext context)
        {
            // 检查是否为异步方法
            bool isAsync = context.ReturnType != null &&
                          typeof(Task).IsAssignableFrom(context.ReturnType);

            if (isAsync && context.ReturnValue is Task task)
            {
                // 异步方法：在任务完成后处理事务
                task.ContinueWith(t => _OnExit(t.Exception ?? context.Exception));
            }
            else
            {
                // 同步方法：直接处理事务
                _OnExit(context.Exception);
            }

            // 内部方法：处理事务的提交或回滚
            void _OnExit(Exception? exception)
            {
                // 添加空检查
                if (_uow == null) return;

                try
                {
                    if (exception == null)
                    {
                        Console.WriteLine("提交事务");
                        //Console.Write(_uow.GetType().FullName);
                        // 无异常时提交事务
                        _uow.Commit();
                    }
                    else
                    {

                        Console.WriteLine($"事务回滚，原因：{exception.Message}");
                        //Console.Write(_uow.GetType().FullName);
                        // 有异常时回滚事务
                        _uow.Rollback();
                    }
                }
                finally
                {
                    //Console.Write(_uow.GetType().FullName);
                    Console.WriteLine("事务结束");
                    // 确保工作单元被释放
                    _uow.Dispose();
                    _uow = null; // 重置为null避免多次处理
                }
            }
        }
    }
}